package com.feel.common.aspect;//package com.box.code.commons.base.message.aspect;

/**
 * @author cxy
 * @date 2022/2/25
 * @QQ 2580040689@qq.com
 **/

import com.feel.common.annotation.ExtApiToken;
import com.feel.modules.app.dto.UserCurrentDto;
import com.feel.common.exception.CommonException;
import com.feel.common.utils.R;
import com.feel.common.redis.RedisUtils;
import com.feel.modules.app.entity.UserEntity;
import com.feel.modules.security.service.UserCurrentService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.UUID;

/**
 * AOP切面
 * 完成功能： 防连点
 * 1)，如果hasToken 根据methodName+userId锁请求，同一用户、同一时间只能有一个该请求有效
 * 1)，如果hasToken = false， 根据methodName锁请求，所有用户、同一时间只能有一个该请求有效
 */
@Aspect
@Slf4j
public class ExtApiTokenAspect {

    RedisUtils redisUtils;

    public ExtApiTokenAspect(RedisUtils redisUtils) {
        this.redisUtils = redisUtils;
    }

    @Autowired
    private UserCurrentService currentService;

    //环绕通知
    @Around(value = "@annotation(around)")
    public Object doBefore(ProceedingJoinPoint proceedingJoinPoint, ExtApiToken around) throws Throwable {
        String methodName = around.methodName();
        boolean hasToken = around.hasToken();
        boolean paramLock = around.paramLock();
        long expire = around.expire();
        String val = UUID.randomUUID().toString();
        Object obj = null;
        //redis锁的key
        String key = "request_" + methodName;


        //如果需要根据当前用户锁请求
        if (hasToken) {

            //获取当前用户
            UserCurrentDto userCurrent = currentService.getUserCurrent();
            UserEntity fUserEntity = userCurrent.getUserEntity();
            Long userId = fUserEntity.getUserId();
            key = key + "_" + userId;
        }
        //如果需要根据当前请求参数锁请求
        if (paramLock) {
            Object[] args = proceedingJoinPoint.getArgs();
            key = key + "_" + getParameterName(args);
        }
        if (redisUtils.lock(key, val, expire)) {
            //放行
            try {
                obj = proceedingJoinPoint.proceed();
            } catch (Exception e) {
                redisUtils.unlock(key, val);
                throw e;
            }
        } else {
            throw new CommonException(R.error("请勿重复提交"));
        }
        return obj;

    }


    public HttpServletRequest getRequest() {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        return request;
    }

    private static String getParameterName(Object[] args) {
        StringBuilder argValues = new StringBuilder();
        for (int i = 0; i < args.length; i++) {
            argValues.append(args[i]);
        }
        return argValues.toString();
    }
  /*  public void getResponse(String msg) throws IOException {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletResponse response = attributes.getResponse();
        response.setHeader("Content-type", "text/html;charset=UTF-8");
        PrintWriter writer = response.getWriter();
        writer.write(msg);
        writer.close();
    }*/
}
